package com.kerry.aop;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.kerry.model.AppLog;
import com.kerry.service.AppLogService;
import com.kerry.service.impl.LogThread;



/**
 * 用户操作日志管理
 * @author lenovo
 */
@Component
@Aspect
@Order(0)
public class AppLogAdvice {
	private Logger log=Logger.getLogger(AppLogAdvice.class);
	
	@Autowired
	private AppLogService logService;

	
	private NamedThreadLocal<Long>  startTimeThreadLocal =new NamedThreadLocal<Long>("StopWatch-StartTime");
	
	@Pointcut("@annotation(com.kerry.aop.MethodLog)")
	private void pointcut() {}
	
	
	@Around("pointcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
		AppLog logEntity=new AppLog();
		long beginTime = System.currentTimeMillis();//1、开始时间
        startTimeThreadLocal.set(beginTime);//线程绑定变量（该数据只有当前请求的线程可见）
		logEntity.setId(UUID.randomUUID().toString().replace("-", ""));
		ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
		HttpServletRequest request=attributes.getRequest();
		
		StringBuffer paramStr=new StringBuffer();
		Enumeration<String> nameList=request.getParameterNames();
		while(nameList.hasMoreElements()){
			String name = nameList.nextElement();
			paramStr.append(name).append("=").append(request.getParameter(name)).append("&");
		}
		Map<String, String> map = getMethodLog(point);  
        logEntity.setPath(request.getRequestURI());
        if(paramStr.length()>0){
        	logEntity.setParam(paramStr.substring(0,paramStr.length()-1));
        }
        logEntity.setModule(map.get("module"));
        logEntity.setFunction(map.get("function"));
        Object object = null;
        try{
        	object=point.proceed();
        	logEntity.setStatus("0");
        	logEntity.setRemark("成功");
        	return object;
        }catch(Exception e){
//        	e.printStackTrace();
        	log.info("AppLogAdvice Exception...... ");
        	logEntity.setStatus("1");
        	logEntity.setRemark("程序出异常");
        	if(e!=null){
        		logEntity.setException(getExceptionTrace(e));
        	}
        }finally{
        	long endTime = System.currentTimeMillis();//1结束时间
    		long time=endTime-startTimeThreadLocal.get();
    		logEntity.setConsumeTime(String.valueOf(time));
    		log.info("Msg:开始写入日志...");
//    		logService.addAppLog(logEntity);
    		new LogThread(logService, logEntity).start();
    		log.info("Msg:日志写入结束");
		}
        return object;
	}
	
	/**
	 * 获取日志注解标注信息  
	 * @param joinPoint
	 * @return
	 * @throws Exception
	 */
    public static Map<String, String> getMethodLog(ProceedingJoinPoint joinPoint)  
            throws Exception {
    	Map<String, String> map=new HashMap<String, String>();
        String targetName = joinPoint.getTarget().getClass().getName();  
        String methodName = joinPoint.getSignature().getName();  
        
        @SuppressWarnings("rawtypes")
		Class targetClass = Class.forName(targetName);  
        Method[] method = targetClass.getMethods();  
        for (Method m : method) {  
            if (m.getName().equals(methodName)) {  
                MethodLog methodCache = m.getAnnotation(MethodLog.class);  
                if (methodCache != null) {  
                	map.put("module", methodCache.module());  
                	map.put("function", methodCache.funtion());
                }  
                break;  
            }  
        }  
        return map;  
    }  
    /**
     * 获取异常信息
     * @param e
     * @return
     */
    public static String getExceptionTrace(Throwable e){
	    StringWriter sw = new StringWriter();
	    PrintWriter pw = new PrintWriter(sw);
	    e.printStackTrace(pw);
	    pw.flush();
	    pw.close();
	    return sw.toString();
	}
}
